# -*- coding: utf-8 -*-
################################################################################
# Copyright (c) 2009 Renzo Sánchez-Silva
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
"""
mongoDB plugin for :mod:`repoze.what` based on pymongo driver.

http://www.mongodb.org

The 'repoze.what' group and permission adapters for mongodb sources.
"""

__author__ = 'Renzo Sánchez-Silva <renzo@edac.unm.edu>'
__copyright__ = '(c) 2009 University of New Mexico'
__license__ = 'Apache 2.0'
__date__ = '2009-09-23' 

__all__ = ['mongodbGroupSourceAdapter', 'mongodbPermissionSourceAdapter']

from repoze.what.adapters import BaseSourceAdapter

class _mongodbAdapter(BaseSourceAdapter):
    """Base class for mongoDB database adapters."""

    def __init__(self, db):
        """
        Create the mongoDB source adapter.

        @param db: The mongodb authorization database connection.

        """
        super(_mongodbAdapter, self).__init__(writable=True)
        self.db = db

    def _get_sections_of_item(self, item):
        sections = []
        filter = {'items': {'$in':[item]}}
        sections_of_item = self.db[self.collection].find(filter)

        for section in sections_of_item:
            sections.append(section['section'])
                        
        return set(sections)                    

    def _get_section_ref(self, section, items = None, fields = None):
        d = {'section':section}
        if items is not None:
            d.update({'items': items})

        return self.db[self.collection].find_one(d, fields = fields)
    
    # Sections 
    
    def _get_all_sections(self):
        sections = {}
        try:
            all_sections = self.db[self.collection].find()
        except:
            msg = ('There was a problem with the source while retrieving the'
                            ' sections')
            raise adapters.SourceError(msg)

        for section in all_sections:
            sections.update({section['section']: set(section['items'])})
        return sections
    
    def _create_section(self, section):
        try:
            what = {'section': section, 'items': [] }
            self.db[self.collection].save(what)
        except:
            msg = "The %r section could not be added" % section
            raise adapters.SourceError(msg)

    def _edit_section(self, section, new_section):
        section_ref = self._get_section_ref(section)

        try:
            section_ref['section'] = new_section
            self.db[self.collection].save(section_ref)
        except:
            msg = "The %r section could not be edited" % section
            raise adapters.SourceError(msg)

    def _delete_section(self, section):
        try:
            section_ref = self._get_section_ref(section)
            self.db[self.collection].remove(section_ref)
        except:
            msg = "The %r section could not be deleted" % section
            raise adapters.SourceError(msg)

    def _section_exists(self, section):
        try:
            value = self._get_section_ref(section, fields = ['_id'])
        except:
            msg = 'There was a problem with the source'
            raise adapters.SourceError(msg)

        if value is not None:
            return True
        else:
            return False

    # Items
            
    def _get_section_items(self, section):
        section_ref = self._get_section_ref(section)
        print section, section_ref
        try:
            # Gets all members of the set.
            items = set(section_ref['items'])
        except:
            msg = ("There was a problem with the source while retrieving the"
                    " %r section") % section
            raise adapters.SourceError(msg)

        return items

    def _include_items(self, section, items):
        try:
            section_ref = self._get_section_ref(section)
            section_ref['items'] += items
            self.db[self.collection].save(section_ref)
        except:
            msg = "The %r items could not be added to the %r section" % \
                      (items, section)
            raise adapters.SourceError(msg)

    def _exclude_items(self, section, items):
        section_ref = self._get_section_ref(section)
        
        for value in items:
            section_ref['items'].remove(value)

        try:
            self.db[self.collection].save(section_ref)
        except:
            msg = "The %r items could not be removed from the %r section" % \
                      (items, section)
            raise adapters.SourceError(msg)

    def _item_is_included(self, section, item):
        section_ref = self._get_section_ref(section)

        if item in section_ref['items']:
            return True
        else:
            return False

# Source adapters

class mongodbGroupSourceAdapter(_mongodbAdapter):
    collection = 'groups'

    def _find_sections(self, credentials):
        """Return group names the authenticated user belongs to."""

        userid = credentials['repoze.what.userid']
        return self._get_sections_of_item(userid)


class mongodbPermissionSourceAdapter(_mongodbAdapter):
    collection = 'permissions'

    def _find_sections(self, group):
        """Return permission names granted to the group."""
        return self._get_sections_of_item(group)
